#ifndef __ENGINE_FACTORY_H__
#define __ENGINE_FACTORY_H__ 1

#include <string>
#include <vector>

#include "embedding_engine.h"
#include "ext_bit_source.h"
#include "packet_source.h"
#include "stegio.h"
#include "properties_reader.h"

/**
 * namespace containing the enums for CEngineFactory
 */
namespace NEngineFactory
{
	/**
	 * enum type that contains the engine types that
	 * can be created by CEngineFactory
	 */
	enum EProtocolEngineType
	{
		PROTOCOL_ENGINETYPE_DEFAULT = 0,
		PROTOCOL_ENGINETYPE_SIMPLEFILE,
		PROTOCOL_ENGINETYPE_FILE,
		PROTOCOL_ENGINETYPE_GUI,
	};

	/**
	 * enum type that contains the embedding engine types that
	 * can be created by CEngineFactory
	 */
	enum EEmbeddingEngineType
	{
		EMBEDDING_ENGINETYPE_DEFAULT = 0,
		EMBEDDING_ENGINETYPE_LSB,
		EMBEDDING_ENGINETYPE_LSB_RAND,
	};

	enum EBitSourceType
	{
		BIT_SOURCETYPE_DEFAULT = 0, // = BYTE BUILDER
		BIT_SOURCETYPE_BYTE_BUILDER,
		BIT_SOURCETYPE_FRAME_BUILDER,
	};
}

/**
 * @brief simple handle class that carries all the
 *        various engines and helper classes
 * @author gpitsch and rpoisel
 *
 * instances of CStegCallHandle are created an deleted by the
 * CEngineFactory
 */
class CStegCallHandle
{
	friend class CEngineFactory;

public:
	CStegCallHandle() :
			mProtocolEngine(NULL),
			mEmbeddingEngine(NULL),
			mBitSource(NULL),
			mExtBitSource(NULL),
			mPacketSource(NULL),
			mPropertiesReader(NULL),
			mUseExternPropertiesReader(false)
			{ }
	virtual ~CStegCallHandle() { }

	/**
	 * @brief simple getter
	 * 
	 * @return the IEmbeddingEngine
	 */
	IEmbeddingEngine* getEmbeddingEngine() const { return mEmbeddingEngine; }

private:
	CStegCallHandle(const CStegCallHandle& );
	CStegCallHandle& operator=(const CStegCallHandle& );

	IStegIO* mProtocolEngine;
	IEmbeddingEngine* mEmbeddingEngine;
	IBitSource* mBitSource;
	IExtBitSource* mExtBitSource;
	IPacketSource* mPacketSource;
	CPropertiesReader* mPropertiesReader;
	bool mUseExternPropertiesReader;
};


/**
 * @brief Factory that creates and destroys instances of CStegCallHandle.
 * @author gpitsch and rpoisel
 *
 * glue code will create and destroy a CStegCallHandle
 * by using createCallHandle() and destroyCallHandle()
 *
 * createCallHandle() in glue code will select the "default"
 * type for pProtocolEngine and pEmbeddingEngine since
 * these are the stable and valid defaults
 *
 * @note unit tests may select different specific combinations
 *       for pProtocolEngine and pEmbeddingEngine but since
 *       some protocol/embedding combinations are invalid
 *       and not supported the caller has to be aware of this
 *
 * currently there may only be @b one active CStegCallHandle
 * at a time.
 *
 * this CStegCallHandle is ref-counted by the CEngineFactory
 * to be sure that multiple createCallHandle() calls get the
 * same instance of the CStegCallHandle and that only the
 * "last" call to destroyCallHandle() really deletes
 * the CStegCallHandle
 */
class CEngineFactory
{
public:

	/**
	 * @brief create/reference a new call handle
	 * @note this CStegCallHandle is ref-counted by the CEngineFactory
	 * @param pRemoteID caller ID of the @b remote peer
	 * @param pProtocolEngine type of IProtocolEngine to be created
	 * @param pEmbeddingEngine type of IEmbeddingEngine to be created
	 *
	 * @return an initialized CStegCallHandle
	 */
	static CStegCallHandle* createCallHandle(const std::string& pRemoteID,
			CPropertiesReader* pExternPropertiesReader = NULL,
			NAudioFormats::SStreamInfo pIoStreamInfo =
					NAudioFormats::SStreamInfo(NAudioFormats::UNKNOWN_WIDTH,
							0,
							NAudioFormats::UNKNOWN_CODEC));

	/**
	 * @brief destroy/un-reference this call handle
	 * @note this CStegCallHandle is ref-counted by the CEngineFactory
	 */
	static void destroyCallHandle(CStegCallHandle** pCallHandle);

	static const std::string sIniSectionName;

protected:

private:
	CEngineFactory();
	CEngineFactory(const CEngineFactory& );
	CEngineFactory& operator=(const CEngineFactory& );

	/**
	 * @brief create a new instance of the CStegCallHandle
	 */
	static CStegCallHandle* createCallHandle_(const std::string& pRemoteID,
			CPropertiesReader* pExternPropertiesReader,
			NAudioFormats::SStreamInfo pIoStreamInfo);

	/**
	 * @brief destroy this instance of the CStegCallHandle
	 */
	static void destroyCallHandle_(CStegCallHandle** pCallHandle);

	static const std::string sDefaultConfigFilename;

	static const std::string sSendOriginalFilename;
	static const std::string sSendModifiedFilename;
	static const std::string sRecvModifiedFilename;
};

#endif // __ENGINE_FACTORY_H__

